package wortubung.inflection;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.json.JSONObject;

import wortubung.JSONConsts;
import wortubung.core.LANG;
import wortubung.util.TransliterateException;

import static wortubung.util.CommonUtils.at;
import static wortubung.util.CommonUtils.eq;
import static wortubung.util.JSONUtils.getString;
import static wortubung.util.JSONUtils.getStringArray;

public final class ConjugationSet {

	private ConjugationResult conjugationResult;
	private Map<CONJUGATION,String[]> conjugations = new HashMap<CONJUGATION,String[]>();
	private String presentParticiple;
	private String pastParticiple;
	private String comment;

	private transient boolean isLatinized = false;

	public ConjugationSet(ConjugationResult conjugationResult, String participePresent, String participePasse) {
		this.conjugationResult = conjugationResult;
		this.presentParticiple = participePresent;
		this.pastParticiple = participePasse;
	}
	
	public void setConjugationResult(ConjugationResult cr) {
		this.conjugationResult = cr;
	}

	public void add(CONJUGATION type, String[] conjs) {
		conjugations.put(type, conjs);
	}

	public void remove(CONJUGATION type) {
		conjugations.remove(type);
	}

	public void inheritFrom(ConjugationSet src) {
		for (CONJUGATION ct : src.conjugations.keySet()) {
			String[] conjs = src.conjugations.get(ct);
			conjugations.put(ct, Arrays.copyOf(conjs, conjs.length));
		}
	}

	public ConjugationResult getConjugationResult() { return conjugationResult; }
	public String[] get(CONJUGATION type) { return conjugations.get(type); }
	public String getPresentParticiple() { return presentParticiple; }
	public String getPastParticiple() { return pastParticiple; }
	public boolean hasParticiples() { return presentParticiple != null || pastParticiple != null; }

	public String getComment() { return comment; }
	public void setComment(String comment) { this.comment = comment; }

	public String participle(String prefix, String verbeSuffix, boolean isPresent) {
		return isPresent ? presentParticiple : pastParticiple;
	}
	
	public void override(HashMap<CONJUGATION,String[]> overrides) {
		if (overrides == null)
			return;
		for (CONJUGATION conj : overrides.keySet()) {
			String[] over = overrides.get(conj);
			if (over.length == 0) {
				remove(conj);
			} else {
				String[] sa = (String[])over;
				String[] result = get(conj);
				for (int j=0; j<sa.length; ++j) {
					if (!"_".equals(sa[j]))
						result[j] = sa[j];
				}
			}
		}
	}

	public ConjugationSet getLatinized(ConjugationResult cr, LANG lang) {
		if ((lang == null) || isLatinized)
			return this;

		String presP = lang.toLatin(this.presentParticiple, true);
		String pastP = lang.toLatin(this.pastParticiple, true);
		String tmp = lang.toLatin(this.comment, true);
		boolean hasDiffs = !eq(presP, this.presentParticiple, true) ||
				           !eq(pastP, this.pastParticiple, true) ||
				           !eq(tmp, this.comment, true);
		ConjugationSet ret = new ConjugationSet(cr, presP, pastP);
		ret.comment = tmp;
		ret.isLatinized = true;
		ret.conjugations = new HashMap<CONJUGATION,String[]>();
		for (CONJUGATION c : this.conjugations.keySet()) {
			String[] sa = this.conjugations.get(c);
			String[] sa1 = new String[sa.length];
			for (int i=sa.length-1; i>=0; --i) {
				tmp = lang.toLatin(sa[i], true);
				hasDiffs |= !eq(tmp, sa[i], true);
				sa1[i] = tmp;
			}
			ret.conjugations.put(c, sa1);
		}
		if (hasDiffs)
			return ret;

		this.isLatinized = true;
		return this;
	}

	public static ConjugationSet fromJSON(ConjugationResult conjugationResult, JSONObject json, LANG lang) throws TransliterateException {
    	String[] sa = getStringArray(json, JSONConsts.PARTICIPLES.name());
    	lang.toVernacular(sa);
    	ConjugationSet ret = new ConjugationSet(conjugationResult, at(sa, 0), at(sa, 1));
    	ret.setComment(getString(json, JSONConsts.COMMENT.name(), null));
    	for (CONJUGATION type : CONJUGATION.values()) {
    		sa = getStringArray(json, type.name());
    		lang.toVernacular(sa);
    		if (sa != null) {
    			lang.toVernacular(sa);
    			ret.add(type, sa);
    		}
    	}
    	return ret;
	}

	public ArrayList<InflectionError> checkError(ConjugationSet toBeChecked) {
		ArrayList<InflectionError> ret = new ArrayList<InflectionError>();

		checkError(ret, "PRESENT_PARTICIPLE", null, getPresentParticiple(), toBeChecked.getPresentParticiple());
		checkError(ret, "PAST_PARTICIPLE", null, getPastParticiple(), toBeChecked.getPastParticiple());
		for (CONJUGATION type : CONJUGATION.values()) {
			String[] expected = get(type);
			String[] actual   = toBeChecked.get(type);
			PERSON[] persons  = PERSON.values();
			for (int j=0; j<persons.length; ++j)
				checkError(ret, type, persons[j], at(expected, j), at(actual, j));
		}

		return ret;
	}

	private void checkError(ArrayList<InflectionError> errors, Object type, PERSON person, String expected, String actual) {
		if (!eq(expected, actual, true))
			errors.add(new InflectionError(getConjugationResult().getVerb(), type, person, expected, actual));
	}
}